package com.telecom.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.zxing.WriterException;
import com.telecom.common.context.UserContext;
import com.telecom.common.convention.errorcode.BaseErrorCode;
import com.telecom.common.convention.result.PageDTO;
import com.telecom.common.convention.result.PageQuery;
import com.telecom.common.convention.exception.ClientException;
import com.telecom.common.convention.exception.ServiceException;
import com.telecom.common.utils.AliOssUtil;
import com.telecom.common.utils.OrderNumberGenerator;
import com.telecom.mapper.MealMapper;
import com.telecom.mapper.OrderCancelMapper;
import com.telecom.mapper.OrderMapper;
import com.telecom.mapper.UserMapper;
import com.telecom.pojo.dto.admin.order.AdminOrderPageQueryRequestDTO;
import com.telecom.pojo.dto.admin.order.OrderCancelRequestDTO;
import com.telecom.pojo.dto.user.order.OrderMealInfoDTO;
import com.telecom.pojo.dto.user.order.OrderPageQueryRequestDTO;
import com.telecom.pojo.dto.user.order.OrderPaymentRequestDTO;
import com.telecom.pojo.entity.Meal;
import com.telecom.pojo.entity.Order;
import com.telecom.pojo.entity.OrderCancel;
import com.telecom.pojo.entity.User;
import com.telecom.pojo.vo.admin.order.AdminOrderDetailVO;
import com.telecom.pojo.vo.admin.order.AdminOrderItemVO;
import com.telecom.pojo.vo.admin.order.RefundRecordVO;
import com.telecom.pojo.vo.user.order.OrderDetailVO;
import com.telecom.pojo.vo.user.order.OrderItemVO;
import com.telecom.pojo.vo.user.order.OrderPickupCodeVO;
import com.telecom.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import com.telecom.common.utils.QRCodeUtil;

/**
 * 订单业务实现类
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;
    
    @Resource
    private OrderCancelMapper orderCancelMapper;
    
    @Resource
    private UserMapper userMapper;
    
    @Resource
    private MealMapper mealMapper;
    
    @Resource
    private OrderNumberGenerator orderNumberGenerator;
    
    @Resource
    private AliOssUtil aliOssUtil;
    
    // 套餐锁对象缓存，key为套餐id，value为锁对象
    private final ConcurrentHashMap<Long, Object> mealLocks = new ConcurrentHashMap<>();

    @Override
    public PageDTO<AdminOrderItemVO> pageQuery(AdminOrderPageQueryRequestDTO queryRequest) {
        // 使用PageHelper进行分页
        PageHelper.startPage(queryRequest.getPageNo(), queryRequest.getPageSize());
        
        // 查询数据（PageHelper会自动添加LIMIT子句）
        List<AdminOrderItemVO> records = orderMapper.selectAdminOrderPage(
                queryRequest.getIdOrUsername(), 
                queryRequest.getStatus()
        );
        
        // 使用PageInfo获取分页信息
        PageInfo<AdminOrderItemVO> pageInfo = new PageInfo<>(records);
        
        // 返回分页结果
        return new PageDTO<>(pageInfo.getTotal(), (long)pageInfo.getPages(), records);
    }

    @Override
    public AdminOrderDetailVO getOrderDetails(Long id) {

        AdminOrderDetailVO orderDetailVO;
        try
        {
            orderDetailVO = orderMapper.selectOrderDetailById(id);
        }
        catch (Exception e)
        {
            throw new ClientException("订单不存在", BaseErrorCode.CLIENT_ERROR);
        }

        if (orderDetailVO == null) {
            throw new ClientException("订单不存在", BaseErrorCode.CLIENT_ERROR);
        }

        return orderDetailVO;

    }

    @Override
    @Transactional
    public void confirmPickup(String orderNumber) {
        // 验证订单是否存在
        Order order = orderMapper.selectByOrderNumber(orderNumber);
        if (order == null) {
            throw new ClientException("订单不存在");
        }
        
        // 验证订单状态
        if (order.getPayStatus() != 1) {
            throw new ClientException("订单未支付，无法确认取餐");
        }
        
        if (order.getPickupStatus() == 1) {
            throw new ClientException("订单已取餐");
        }
        
        if (order.getPickupStatus() == 2) {
            throw new ClientException("订单已取消");
        }
        
        // 验证取餐日期：只能在套餐的date当天取餐
        Meal meal = mealMapper.selectById(order.getMealId());
        if (!LocalDate.now().equals(meal.getDate())) {
            throw new ClientException("只能在套餐所属日期当天取餐");
        }
        
        // 更新取餐状态为已取餐
        try {
            orderMapper.updatePickupStatusByOrderNumber(orderNumber, 1);
        }
        catch (Exception e)
        {
            throw new ServiceException("确认取餐失败", BaseErrorCode.SERVICE_ERROR);
        }

        
        log.info("订单 {} 确认取餐成功", orderNumber);
    }

    @Override
    @Transactional
    public void cancelOrder(OrderCancelRequestDTO cancelRequest) {
        // 验证订单是否存在
        Order order = orderMapper.selectById(cancelRequest.getId());
        if (order == null) {
            throw new ClientException("订单不存在");
        }
        
        // 验证订单状态
        if (order.getPickupStatus() == 1) {
            throw new ClientException("订单已取餐，无法取消");
        }
        
        if (order.getPickupStatus() == 2) {
            throw new ClientException("订单已取消");
        }
        
        // 验证退款金额
        if (cancelRequest.getRefundAmount().compareTo(order.getActualAmount()) > 0) {
            throw new ClientException("退款金额不能大于实付金额");
        }
        
        // 更新订单状态为已取消
        try {
            orderMapper.updateOrderStatus(
                    cancelRequest.getId(),
                    2, // 退款状态
                    2  // 取消状态
            );
        }
        catch (Exception e)
        {
            throw new ServiceException("更新订单状态失败", BaseErrorCode.SERVICE_ERROR);
        }
        
        // 释放套餐库存（下单时已锁定库存，取消时需要释放）
        if (order.getMealId() != null) {
            try {
                // 查询当前餐品信息
                Meal meal = mealMapper.selectById(order.getMealId());
                if (meal != null && meal.getSalesCount() != null && meal.getSalesCount() > 0) {
                    // 减少销量
                    Meal updateMeal = Meal.builder()
                            .id(order.getMealId())
                            .salesCount(meal.getSalesCount() - 1)
                            .updateTime(LocalDateTime.now())
                            .build();

                    int result = mealMapper.updateById(updateMeal);
                    if (result > 0) {
                        log.info("订单取消，套餐 {} 销量减少 1，当前销量：{}", order.getMealId(), meal.getSalesCount() - 1);
                    } else {
                        log.warn("订单取消，但套餐 {} 销量减少失败", order.getMealId());
                    }
                } else {
                    log.warn("订单取消，但套餐 {} 当前销量为0或不存在，无法减少", order.getMealId());
                }
            } catch (Exception e) {
                log.error("订单取消时减少套餐销量失败，套餐ID：{}，错误信息：{}", order.getMealId(), e.getMessage());
                throw new ServiceException("订单取消时减少套餐销量失败", BaseErrorCode.SERVICE_ERROR);
                // 销量更新失败不影响订单取消流程，只记录日志
            }
        }


        // 创建取消记录
        OrderCancel orderCancel = OrderCancel.builder()
                .orderId(cancelRequest.getId())
                .cancelReason(cancelRequest.getCancelReason())
                .refundAmount(cancelRequest.getRefundAmount())
                .refundStatus(1) // 设为退款成功（简化流程）
                .operatorId(null) // 管理员操作，这里需要从上下文获取操作员ID
                .cancelTime(LocalDateTime.now())
                .refundTime(LocalDateTime.now()) // 模拟即时退款
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        
        try {
            orderCancelMapper.insert(orderCancel);
        }
        catch (Exception e)
        {
            throw new ServiceException("创建取消记录失败", BaseErrorCode.SERVICE_ERROR);
        }


        // 退款到用户余额
        User user = userMapper.selectById(order.getUserId());
        if (user != null) {
            BigDecimal newBalance = user.getBalance().add(cancelRequest.getRefundAmount());
            user.setBalance(newBalance);
            user.setUpdateTime(LocalDateTime.now());
            userMapper.updateById(user);
            log.info("用户 {} 退款 {} 元，当前余额：{}", user.getUsername(), 
                    cancelRequest.getRefundAmount(), newBalance);
        }
        
        log.info("订单 {} 取消成功，退款金额：{}", order.getOrderNumber(), 
                cancelRequest.getRefundAmount());
    }

    @Override
    public PageDTO<RefundRecordVO> getRefundPage(PageQuery pageQuery) {
        // 使用PageHelper进行分页
        PageHelper.startPage(pageQuery.getPageNo(), pageQuery.getPageSize());
        
        // 查询数据
        List<RefundRecordVO> records = orderCancelMapper.selectRefundPage();
        
        // 使用PageInfo获取分页信息
        PageInfo<RefundRecordVO> pageInfo = new PageInfo<>(records);
        
        // 返回分页结果
        return new PageDTO<>(pageInfo.getTotal(), (long)pageInfo.getPages(), records);
    }

    @Override
    @Transactional
    public Long createOrder(Long mealId, Long userId) {
        log.info("创建订单，套餐ID：{}，用户ID：{}", mealId, userId);

        // 获取套餐对应的锁对象
        Object lock = mealLocks.computeIfAbsent(mealId, k -> new Object());
        
        Meal meal;
        synchronized (lock) {
            meal = mealMapper.selectById(mealId);
            if (meal == null) {
                throw new ClientException("套餐不存在");
            }

            if (!meal.getIsAvailable()) {
                throw new ClientException("套餐未启用");
            }

            // 检查套餐日期，用户必须至少提前一天下单
            if (!LocalDate.now().isBefore(meal.getDate())) {
                throw new ClientException("套餐已过预订时间，无法下单");
            }

            // 检查库存（下单时立即检查最新库存）
            if (meal.getSalesCount() >= meal.getStock()){
                throw new ClientException("套餐已售罄");
            }



            // 关键：立即锁定库存（增加销量）
            Meal updateMeal = Meal.builder()
                    .id(mealId)
                    .salesCount(meal.getSalesCount() + 1)
                    .updateTime(LocalDateTime.now())
                    .build();

            int result = mealMapper.updateById(updateMeal);
            if (result <= 0) {
                throw new ServiceException("锁定库存失败", BaseErrorCode.SERVICE_ERROR);
            }
            log.info("库存锁定成功，套餐 {} 销量增加 1，当前销量：{}", mealId, meal.getSalesCount() + 1);
        }
        // 锁释放，后续操作不需要锁保护

        //生成订单号
        String orderNumber = orderNumberGenerator.generateOrderNumber();
        log.info("生成订单号：{}", orderNumber);

        //根据订单号生成二维码
        String qrcode;
        try {
            // 生成二维码图片
            byte[] qrCodeBytes = QRCodeUtil.generateQRCode(orderNumber, 300, 300);

            // 上传到OSS并获取访问URL
            String fileName = "qrcode/" + orderNumber + "_" + System.currentTimeMillis() + ".png";
            qrcode = aliOssUtil.upload(qrCodeBytes, fileName);
            log.info("二维码上传成功，访问URL：{}", qrcode);
        } catch (WriterException | IOException e) {
            log.error("生成二维码失败", e);
            // 事务会自动回滚，无需手动回退库存
            throw new ServiceException("生成二维码失败", BaseErrorCode.SERVICE_ERROR);
        }

        Order order = Order.builder()
                .orderNumber(orderNumber)
                .mealId(mealId)
                .userId(userId)
                .payStatus(0)
                .pickupStatus(0)
                .totalAmount(meal.getPrice())
                .actualAmount(BigDecimal.valueOf(0))
                .qrCodeUrl(qrcode)
                .isSatisfied(null)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();

        int result = orderMapper.insert(order);
        if (result <= 0) {
            // 事务会自动回滚，无需手动回退库存
            throw new ServiceException("插入订单失败", BaseErrorCode.SERVICE_ERROR);
        }

        // 返回自动生成的订单ID
        return order.getId();
    }

    @Override
    @Transactional
    public void userCancelOrder(Long id) {
        Order order = orderMapper.selectById(id);
        if (order == null) {
            throw new ClientException("订单不存在");
        }
        if (order.getPickupStatus() == 1){
            throw new ClientException("订单已取餐，无法取消");
        }
        if (order.getPickupStatus() ==2){
            throw new ClientException("订单已取消，无法重复提交");
        }
        if (order.getPayStatus() == 2){
            throw new ClientException("订单已退款，无法重复提交");
        }

        //查询套餐日期，用户能取消的规则是至少比套餐日期提前一天
        Meal meal = mealMapper.selectById(order.getMealId());
        if(!LocalDate.now().isBefore(meal.getDate())){
            throw new ClientException("订单已过取消时间，无法取消");
        }
        
        // 释放套餐库存（下单时已锁定库存，取消时需要释放）
        if (order.getMealId() != null) {
            try {
                // 查询当前餐品信息
                Meal currentMeal = mealMapper.selectById(order.getMealId());
                if (currentMeal != null && currentMeal.getSalesCount() != null && currentMeal.getSalesCount() > 0) {
                    // 减少销量
                    Meal updateMeal = Meal.builder()
                            .id(order.getMealId())
                            .salesCount(currentMeal.getSalesCount() - 1)
                            .updateTime(LocalDateTime.now())
                            .build();

                    int result = mealMapper.updateById(updateMeal);
                    if (result > 0) {
                        log.info("订单取消，套餐 {} 销量减少 1，当前销量：{}", order.getMealId(), currentMeal.getSalesCount() - 1);
                    } else {
                        log.warn("订单取消，但套餐 {} 销量减少失败", order.getMealId());
                    }
                } else {
                    log.warn("订单取消，但套餐 {} 当前销量为0或不存在，无法减少", order.getMealId());
                }
            } catch (Exception e) {
                log.error("订单取消时减少套餐销量失败，套餐ID：{}，错误信息：{}", order.getMealId(), e.getMessage());
                throw new ServiceException("订单取消时减少套餐销量失败", BaseErrorCode.SERVICE_ERROR);
            }
        }
        
        try {
            // 更新订单状态和更新时间
            orderMapper.updateOrderStatus(id, 2, 2);
        }
        catch (Exception e)
        {
            throw new ServiceException("更新订单状态失败", BaseErrorCode.SERVICE_ERROR);
        }
        log.info("更新订单状态成功，订单ID：{}", id);

        // 创建取消记录
        OrderCancel orderCancel = OrderCancel.builder()
                .orderId(id)
                .cancelReason("用户主动取消")
                .refundAmount(order.getActualAmount())
                .refundStatus(1)    //模拟即时退款
                .operatorId(null)   //表示用户主动取消
                .cancelTime(LocalDateTime.now())
                .refundTime(LocalDateTime.now())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        try {
            orderCancelMapper.insert(orderCancel);
        }
        catch (Exception e)
        {
            throw new ServiceException("保存取消记录失败", BaseErrorCode.SERVICE_ERROR);
        }

        // 退款到用户余额
        User user = userMapper.selectById(order.getUserId());
        if (user != null) {
            BigDecimal newBalance = user.getBalance().add(order.getActualAmount());
            user.setBalance(newBalance);
            user.setUpdateTime(LocalDateTime.now());
            userMapper.updateById(user);
            log.info("用户 {} 退款 {} 元，当前余额：{}", user.getUsername(),
                    order.getActualAmount(), newBalance);
        }

        log.info("订单 {} 取消成功，退款金额：{}", order.getOrderNumber(),
                order.getActualAmount());
    }

    @Override
    @Transactional
    public void updateOrderPayStatus(OrderPaymentRequestDTO paymentRequest) {
        Long id = paymentRequest.getId();
        Order order = orderMapper.selectById(id);
        if (order == null) {
            throw new ClientException("订单不存在");
        }
        if (order.getPayStatus() == 1){
            throw new ClientException("订单已支付，请勿重复提交");
        }
        if (order.getPayStatus() == 2){
            throw new ClientException("订单已取消，请勿重复提交");
        }
        
        // 检查用户余额是否充足
        User user = userMapper.selectById(order.getUserId());
        if (user == null) {
            throw new ClientException("用户不存在");
        }
        if (user.getBalance().compareTo(order.getTotalAmount()) < 0) {
            throw new ClientException("账户余额不足，请先充值");
        }
        
        // 扣除用户余额
        BigDecimal newBalance = user.getBalance().subtract(order.getTotalAmount());
        user.setBalance(newBalance);
        user.setUpdateTime(LocalDateTime.now());
        try {
            userMapper.updateById(user);
            log.info("用户 {} 支付 {} 元，余额从 {} 更新为 {}", 
                    user.getUsername(), order.getTotalAmount(), 
                    user.getBalance().add(order.getTotalAmount()), newBalance);
        } catch (Exception e) {
            log.error("扣除用户余额失败，用户ID：{}，错误信息：{}", user.getId(), e.getMessage());
            throw new ServiceException("扣除用户余额失败", BaseErrorCode.SERVICE_ERROR);
        }
        
        //更新用户订单状态、支付金额、取餐方式和备注
        try {
            orderMapper.updatePayStatusAndOrderInfo(id, 1, order.getTotalAmount(), 
                paymentRequest.getDiningType(), paymentRequest.getRemark());
        }
        catch (Exception e)
        {
            throw new ServiceException("用户支付操作失败", BaseErrorCode.SERVICE_ERROR);
        }
        
        // 支付成功，库存已在下单时锁定，无需再次操作
        log.info("订单支付完成，订单ID：{}，金额：{}", id, order.getTotalAmount());
    }

    @Override
    public void rating(long id, boolean isSatisfied) {
        Order order = orderMapper.selectById(id);
        if (order == null) {
            throw new ClientException("订单不存在");
        }
        if (order.getPickupStatus() != 1){
            throw new ClientException("订单未取餐，无法评价");
        }
        if (order.getIsSatisfied() != null){
            throw new ClientException("订单已评价，请勿重复提交");
        }

        //用餐评价
        try {
            orderMapper.updateComment(id, isSatisfied);
        } catch (Exception e) {
            throw new ServiceException("用户评价操作失败", BaseErrorCode.SERVICE_ERROR);
        }
    }

    @Override
    public PageDTO<OrderItemVO> userPageQuery(OrderPageQueryRequestDTO queryRequest) {
        log.info("用户端订单分页查询:{}",queryRequest);

        // 获取当前用户ID
        Long userId = UserContext.getUser();
        
        // 启用PageHelper分页
        PageHelper.startPage(queryRequest.getPageNo(), queryRequest.getPageSize());
        List<OrderMealInfoDTO> records = orderMapper.userSelectPageByCondition(userId, queryRequest.getStatus());

        // 先创建PageInfo获取分页信息
        PageInfo<OrderMealInfoDTO> pageInfo = new PageInfo<>(records);
        
        // 转换OrderMealInfoDTO列表为OrderItemVO列表
        List<OrderItemVO> orderItemVOList = records.stream().map(record -> {
            OrderItemVO orderItemVO = new OrderItemVO();
            BeanUtils.copyProperties(record, orderItemVO);
            
            // 根据payStatus和pickupStatus设置status
            if (record.getPayStatus() == 2 && record.getPickupStatus() == 2) {
                // 已取消状态
                orderItemVO.setStatus(0);
            } else if (record.getPayStatus() == 0) {
                // 待支付状态
                orderItemVO.setStatus(1);
            } else if (record.getPayStatus() == 1 && record.getPickupStatus() == 0) {
                // 待取餐状态
                orderItemVO.setStatus(2);
            } else if (record.getPayStatus() == 1 && record.getPickupStatus() == 1) {
                // 已完成状态
                orderItemVO.setStatus(3);
            }
            
            return orderItemVO;
        }).collect(Collectors.toList());

        // 创建分页DTO，使用原始PageInfo的分页信息，但返回转换后的VO列表
        PageDTO<OrderItemVO> userPageResult = new PageDTO<>(pageInfo.getTotal(), (long) pageInfo.getPages(), orderItemVOList);

        log.info("用户端订单分页查询成功，总数：{}，当前页数据量：{}", pageInfo.getTotal(), orderItemVOList.size());
        return userPageResult;
    }

    @Override
    public OrderPickupCodeVO getOrderPickupCode(Long id) {
        log.info("获取订单取餐码：{}",id);
        Order order = orderMapper.selectById(id);
        if (order == null) {
            throw new ClientException("订单不存在");
        }
        if (order.getPayStatus() != 1) {
            throw new ClientException("订单未支付，请先支付");
        }
        OrderPickupCodeVO orderPickupCodeVO = new OrderPickupCodeVO();
        BeanUtils.copyProperties(order, orderPickupCodeVO);
        return orderPickupCodeVO;
    }

    @Override
    public OrderDetailVO getUserOrderDetails(Long id) {
        log.info("获取用户订单详情：{}",id);
        Order order = orderMapper.selectById(id);
        if (order == null) {
            throw new ClientException("订单不存在");
        }
        OrderDetailVO orderDetails = new OrderDetailVO();
        BeanUtils.copyProperties(order, orderDetails);

        // 根据payStatus和pickupStatus设置status
        if (order.getPayStatus() == 2 && order.getPickupStatus() == 2) {
            // 已取消状态
            orderDetails.setStatus(0);
        } else if (order.getPayStatus() == 0) {
            // 待支付状态
            orderDetails.setStatus(1);
        } else if (order.getPayStatus() == 1 && order.getPickupStatus() == 0) {
            // 待取餐状态
            orderDetails.setStatus(2);
        } else if (order.getPayStatus() == 1 && order.getPickupStatus() == 1) {
            // 已完成状态
            orderDetails.setStatus(3);
        }

        // 获取订单对应的套餐信息
        if (order.getMealId() != null) {
            Meal meal = mealMapper.selectById(order.getMealId());
            if (meal != null) {
                orderDetails.setMeals(List.of(meal));
            }
        }

        return orderDetails;
    }



}